package classfile

// 代表某一个方法的Code属性的结构体
type CodeAttribute struct {
	cp                   ConstantPool
	attributeLength      uint32                 // 属性长度
	maxStack             uint16                 // 最大栈深度
	maxLocals            uint16                 // 最大局部变量表长度
	codeLength           uint32                 // 字节码数量
	code                 []byte                 // 字节码，每一个字节码都是一个byte
	exceptionTableLength uint16                 // 异常表长度
	exceptionTable       []*ExceptionTableEntry // 异常表
	attributeCOunt       uint16                 // 方法中属性的个数
	attributes           []AttributeInfo        // 属性
}

type ExceptionTableEntry struct {
	startPc   uint16 //此异常处理器有效范围的pc计数器的起始值
	endPc     uint16 // 结束值
	handlerPc uint16 // 遇到异常时，pc寄存器跳到该行继续执行
	catchType uint16 //此异常处理器可以处理的异常的类型,是对常量池的一个有效索引，常量池此位置必须是一个CONSTANT_Class结构
}

func (self *CodeAttribute) readInfo(reader *ClassReader) {
	// 最大栈深度
	self.maxStack = reader.ReadUint16()
	// 最大局部变量表槽数
	self.maxLocals = reader.ReadUint16()
	// code属性的长度，也就是字节码的长度。字节码中包括操作码和操作数
	self.codeLength = reader.ReadUint32()
	// 读取字节码内容
	self.code = reader.ReadBytes(self.codeLength)
	// 异常表
	self.exceptionTable = readExceptionTable(reader)
	// 读取Code属性的属性。Code属性可以有自己的属性
	self.attributes = readAttributes(reader, self.cp)

}

func readExceptionTable(reader *ClassReader) []*ExceptionTableEntry {
	// 异常表长度
	length := reader.ReadUint16()
	// 创建异常表
	table := make([]*ExceptionTableEntry, length)
	for i := range table {
		// 创建异常表的每一个节点
		table[i] = &ExceptionTableEntry{
			// 此节点处理范围的起始PC
			startPc:   reader.ReadUint16(),
			// 此节点处理范围的结束PC
			endPc:     reader.ReadUint16(),
			// 发生此节点可以处理的异常后，程序跳转到这个PC位置继续执行
			handlerPc: reader.ReadUint16(),
			// 此节点可以处理哪个异常类，这是一个指向常量池的索引，常量池此位置必须是一个CONSTANT_Class_INFO结构
			catchType: reader.ReadUint16(),
		}
	}
	return table
}

// 一些get方法，用于暴露私有变量
func (self *CodeAttribute) Cp() ConstantPool                       { return self.cp }
func (self *CodeAttribute) AttributeLength() uint32                { return self.attributeLength }
func (self *CodeAttribute) MaxStack() uint16                       { return self.maxStack }
func (self *CodeAttribute) MaxLocals() uint16                      { return self.maxLocals }
func (self *CodeAttribute) CodeLength() uint32                     { return self.codeLength }
func (self *CodeAttribute) Code() []byte                           { return self.code }
func (self *CodeAttribute) ExceptionTableLength() uint16           { return self.exceptionTableLength }
func (self *CodeAttribute) ExceptionTable() []*ExceptionTableEntry { return self.exceptionTable }
func (self *CodeAttribute) AttributeCOunt() uint16                 { return self.attributeCOunt }
func (self *CodeAttribute) Attributes() []AttributeInfo            { return self.attributes }
